/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package br.com.foxinline.servico;

import br.com.foxinline.enums.TipoDocumento;
import br.com.foxinline.generico.ServicoGenerico;
import br.com.foxinline.modelo.Averbacao;
import br.com.foxinline.modelo.Forus;
import br.com.foxinline.modelo.Imovel;
import br.com.foxinline.modelo.Prefeitura;
import br.com.nordestefomento.jrimum.bopepo.BancoSuportado;
import br.com.nordestefomento.jrimum.bopepo.guia.Guia;
import br.com.nordestefomento.jrimum.bopepo.view.guia.GuiaViewer;
import br.com.nordestefomento.jrimum.domkee.financeiro.banco.febraban.Agencia;
import br.com.nordestefomento.jrimum.domkee.financeiro.banco.febraban.guia.Arrecadacao;
import br.com.nordestefomento.jrimum.domkee.financeiro.banco.febraban.guia.CodigoDeIdentificacaoFebraban;
import br.com.nordestefomento.jrimum.domkee.financeiro.banco.febraban.guia.Convenio;
import br.com.nordestefomento.jrimum.domkee.financeiro.banco.febraban.guia.OrgaoRecebedor;
import br.com.nordestefomento.jrimum.domkee.financeiro.banco.febraban.guia.TipoSeguimento;
import br.com.nordestefomento.jrimum.domkee.financeiro.banco.febraban.guia.TipoValorReferencia;
import br.com.nordestefomento.jrimum.utilix.ObjectUtil;
import com.lowagie.text.Document;
import com.lowagie.text.DocumentException;
import com.lowagie.text.pdf.PdfContentByte;
import com.lowagie.text.pdf.PdfImportedPage;
import com.lowagie.text.pdf.PdfReader;
import com.lowagie.text.pdf.PdfWriter;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.imageio.ImageIO;
import javax.persistence.NoResultException;
import javax.persistence.NonUniqueResultException;
import javax.persistence.Query;
import org.jrimum.bopepo.pdf.Files;
import org.jrimum.utilix.ClassLoaders;

/**
 *
 * @author elyjunior
 */
@Stateless
public class ForusServico extends ServicoGenerico<Forus> {

    @EJB
    AverbacaoServico averbacaoServico;
    private Long quantidadeRegistrosResults;
    @EJB
    private PrefeituraServico prefeituraServico;

    public ForusServico() {
        super(Forus.class);
    }

//    public void gerarForus(Imovel imovel) {
//        List<Averbacao> averbacoes = averbacaoServico.getPorImovel(imovel);
//        for (Averbacao aver : averbacoes) {
//            if (aver.getTipoAverbacao() == TipoAverbacao.MUDANCA_NOME
//                    || aver.getTipoAverbacao() == TipoAverbacao.TRANSFERENCIA) {
////                Boolean possuiForus = possuiForus(aver);
////                if (possuiForus) {
////                    System.out.println("POSSUI");
////                } else {
////                    System.out.println("NAO POSSUI");
//
////            Forus forus = new Forus();
////            forus.setDataForus(new Date());
////            forus.setAverbacao(averbacao);
////            forus.setValor(BigDecimal.TEN);
//                }
//
//            }
//        }
//    }
    public void gerarForus(Averbacao aver) {
        Forus f = possuiForus(aver);
        System.out.println(f);
//        if (f != null) {
//            System.out.println("POSSUI");
//        } else {
//            Forus forus = new Forus();
//            forus.setAverbacao(aver);
//            forus.setDataForus(new Date());
//            forus.setValor(BigDecimal.TEN);
//            save(forus);
//        }
    }

    /**
     *
     * @param ForusAverbacao
     */
    public List<Forus> forusByAverbacao(Averbacao averbacao, Imovel imovel) {
        String sql = "SELECT f FROM Forus f JOIN f.averbacao a JOIN a.imovel i WHERE a.id= :averbacao OR i.id = :imovel order by f.dataForus desc";
        Query query = getEntityManager().createQuery(sql);
        query.setParameter("averbacao", averbacao.getId());
        query.setParameter("imovel", imovel.getId());
        if (query.getResultList() != null) {
            return (List<Forus>) query.getResultList();
        }
        return new ArrayList<Forus>();
    }

    public List<Forus> forusPendentes(Averbacao averbacao, Imovel imovel) {
        String sql = "SELECT f FROM Forus f JOIN f.averbacao a JOIN a.imovel i WHERE a.id= :averbacao OR i.id = :imovel AND f.pago = FALSE order by f.dataForus desc";
        Query query = getEntityManager().createQuery(sql);
        query.setParameter("averbacao", averbacao.getId());
        query.setParameter("imovel", imovel.getId());
        if (query.getResultList() != null) {
            return (List<Forus>) query.getResultList();
        }
        return new ArrayList<Forus>();
    }

    public BigDecimal somaForus(Imovel imovel) {
        String sql = "SELECT SUM(f.valor) FROM Forus f JOIN f.averbacao a JOIN a.imovel i WHERE i.id = :imovel AND f.pago = FALSE";
        Query query = getEntityManager().createQuery(sql);

        query.setParameter("imovel", imovel.getId());

        BigDecimal result = (BigDecimal) query.getSingleResult();

        if (result == null) {
            return new BigDecimal(0);
        }

        return result;
    }

    public Forus possuiForus(Averbacao averbacao) {
        Forus forus;
        Calendar calendar = Calendar.getInstance();
        String strDateFrom = calendar.get(Calendar.YEAR) + "/01/01";
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy/MM/dd");
        Date dateFrom = null, dateTo = null;
        try {
            dateFrom = formatter.parse(strDateFrom);
            String strDateTo = calendar.get(Calendar.YEAR) + "/12/31";
            dateTo = formatter.parse(strDateTo);
        } catch (ParseException ex) {
            Logger.getLogger(ForusServico.class.getName()).log(Level.SEVERE, null, ex);
        }
        String sql = "Select f from Forus f JOIN f.averbacao a WHERE f.dataForus BETWEEN :from AND :to AND a.id = :aver";
        Query query = getEntityManager().createQuery(sql);
        query.setParameter("from", dateFrom);
        query.setParameter("to", dateTo);
        query.setParameter("aver", averbacao.getId());


        try {
            forus = (Forus) query.getResultList().get(0);

        } catch (NoResultException nr) {
            return null;
        } catch (NonUniqueResultException nre) {
            return null;
        } catch (Exception e) {
            return null;
        }

        return forus;
    }

    public List<Averbacao> getAverbacoes(Imovel imovel) {
        return averbacaoServico.getPorImovel(imovel);
    }

    public void imprimirBoleto(Forus forus) throws IOException {

        List<Prefeitura> prefeituras = prefeituraServico.findAll();
        Prefeitura prefeitura = prefeituras.get(prefeituras.size() - 1);
        String agencia[] = prefeitura.getBancoAgencia().split("-");
        BufferedImage imageOrgaoRecebedor = null;
        if (prefeitura.getLogo() != null && prefeitura.getLogo().getUrl() != null && !prefeitura.getLogo().getUrl().isEmpty()) {
            imageOrgaoRecebedor = ImageIO.read(new File(prefeitura.getLogo().getUrl() + prefeitura.getLogo().getNome()));
        }

        /*
         * ====================================== Informando os dados do
         * contribuinte ======================================
         */

        String nome = forus.getAverbacao().getImovel().getProprietarios().get(0).getTipoDocumento().getTipo().equals(TipoDocumento.CPF.getTipo()) ? forus.getAverbacao().getImovel().getProprietarios().get(0).getNome() : forus.getAverbacao().getImovel().getProprietarios().get(0).getNomeFantasia();
        String documento = forus.getAverbacao().getImovel().getProprietarios().get(0).getTipoDocumento().getTipo().equals(TipoDocumento.CPF.getTipo()) ? forus.getAverbacao().getImovel().getProprietarios().get(0).getCpf() : forus.getAverbacao().getImovel().getProprietarios().get(0).getCnpj();

        br.com.nordestefomento.jrimum.domkee.financeiro.banco.febraban.guia.Contribuinte contribuinte = new br.com.nordestefomento.jrimum.domkee.financeiro.banco.febraban.guia.Contribuinte("NOME: " + nome, documento == null || documento.length() == 0 ? "00000000000" : documento);

        /*
         * ====================================== Informando os dados do
         * orgao/empresa recebedor ======================================
         */

        OrgaoRecebedor orgaoRecebedor = new OrgaoRecebedor(prefeitura.getNome(), TipoSeguimento.PREFEITURA);
        orgaoRecebedor.setCodigoDeIdentificacaoFebraban(new CodigoDeIdentificacaoFebraban(prefeitura.getCodigoFebraban()));
        // Se houver uma imagem(Ex: logo) do órgão recebedor...
        if (ObjectUtil.isNotNull(imageOrgaoRecebedor)) {
            orgaoRecebedor.setImgLogo(imageOrgaoRecebedor);
        }

        /*
         * ====================================== Informando os dados do
         * convênio ======================================
         */
        Convenio convenio = new Convenio();
        if (agencia.length == 2) {
            convenio.setAgencia(new Agencia(Integer.parseInt(agencia[0]), agencia[1]));
        }
        br.com.nordestefomento.jrimum.domkee.financeiro.banco.febraban.Banco banco = BancoSuportado.BANCO_DO_BRASIL.create();
        br.com.nordestefomento.jrimum.domkee.financeiro.banco.febraban.ContaBancaria contaB = new br.com.nordestefomento.jrimum.domkee.financeiro.banco.febraban.ContaBancaria();
        contaB.setAgencia(new Agencia(Integer.parseInt(agencia[0]), agencia[1]));
        if (prefeitura.getBancoCarteira() != null) {
            br.com.nordestefomento.jrimum.domkee.financeiro.banco.febraban.Carteira carteira = new br.com.nordestefomento.jrimum.domkee.financeiro.banco.febraban.Carteira(Integer.parseInt(prefeitura.getBancoCarteira()), br.com.nordestefomento.jrimum.domkee.financeiro.banco.febraban.TipoDeCobranca.COM_REGISTRO);
            contaB.setCarteira(carteira);
        }
        banco.addContaBancaria(contaB);
        convenio.setBanco(banco);
        convenio.setNumero(Integer.parseInt(prefeitura.getBancoNumeroConvenio()));

        /*
         * ====================================== Informando dados da
         * Arrecadação ======================================
         */
        Arrecadacao arrecadacao = new Arrecadacao(orgaoRecebedor, contribuinte, convenio);

        String nossoNumero = forus.getId() + "00";
        while (nossoNumero.length() < 14) {
            nossoNumero = "0" + nossoNumero;
        }

        //TODO Alterar Codigo Nosso Numero
        nossoNumero = "555" + nossoNumero;
        arrecadacao.setNossoNumero(nossoNumero);

        arrecadacao.setValorDocumento(forus.getValor());
        arrecadacao.setTipoValorReferencia(TipoValorReferencia.QUANTIDADE_DE_MOEDA_COM_DV_MODULO_10);
        arrecadacao.setDataDoDocumento(GregorianCalendar.getInstance().getTime());
        File templatePersonalizado = new File(ClassLoaders.getResource("/br/com/foxinline/relatorio/iptu/MODELO_PARCELA_REQUERIMENTO.pdf").getFile());
        Calendar calendar = GregorianCalendar.getInstance();

        calendar.setTime(new Date());
        int x = calendar.get(Calendar.YEAR);
        int d = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
        calendar.set(x, Calendar.DECEMBER, d);
//        calendar.add(Calendar.DAY_OF_MONTH, 2);
        arrecadacao.setDataDoVencimento(calendar.getTime());

        /*
         * ====================================== Informando dados da Guia
         * ======================================
         */

        Guia guia = new Guia(arrecadacao);

        guia.setInstrucaoAoCaixa1("PAGAMENTO SOMENTE À VISTA NO BANCO DO BRASIL.");
        guia.setInstrucaoAoCaixa2("PREFERENCIAMENTE DEVE SER PAGA NOS TERMINAIS DE AUTO-ATENDIMENTO,");
        guia.setInstrucaoAoCaixa3("CORRESPONDENTES BANCÁRIOS E INTERNET");

        // GuiaViewer é o responsável por prover uma visualização da guia.
        GuiaViewer guiaViewer = new GuiaViewer(guia);

        // Se houver um template personalizado, com campos extras, novas informações podem
        // ser adicionadas.
        if (ObjectUtil.isNotNull(templatePersonalizado)) {
            guia.addTextosExtras("txtValorDocumento2", "R$ " + arrecadacao.getValorDocumento().toString());
            guia.addTextosExtras("txtParcela", "UNICA");
            guia.addTextosExtras("txtParcela1", "UNICA");
            guia.addTextosExtras("txtNossoNumero", arrecadacao.getNossoNumero());
            guia.addTextosExtras("txtNossoNumero1", arrecadacao.getNossoNumero());
            guiaViewer = new GuiaViewer(guia);
            guiaViewer.setTemplate(templatePersonalizado);
        }


        // Gerando o arquivo. No caso o arquivo mencionado será salvo na mesma
        // pasta do projeto. Outros exemplos:
        // WINDOWS: boletoViewer.getAsPDF("C:/Temp/MeuBoleto.pdf");
        // LINUX: boletoViewer.getAsPDF("/home/temp/MeuBoleto.pdf");
        // File arquivoPdf = guiaViewer.getPdfAsFile("/opt/MinhaPrimeiraGuia.pdf");

        try {
            List<byte[]> boletosEmBytes = new ArrayList<byte[]>();
            boletosEmBytes.add(guiaViewer.getPdfAsByteArray());
            File arq = Files.bytesToFile("carneRequerimento.pdf", mergeFilesInPages(boletosEmBytes));
            RelatorioServico.genReport(Files.fileToBytes(arq));

            // Mostrando o boleto gerado na tela.
        } catch (DocumentException ex) {
            Logger.getLogger(RequerimentoServico.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(RequerimentoServico.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void imprimirBoletoForus(Imovel imovel) throws IOException {

        List<Prefeitura> prefeituras = prefeituraServico.findAll();
        Prefeitura prefeitura = prefeituras.get(prefeituras.size() - 1);
        String agencia[] = prefeitura.getBancoAgencia().split("-");
        BufferedImage imageOrgaoRecebedor = null;
        if (prefeitura.getLogo() != null && prefeitura.getLogo().getUrl() != null && !prefeitura.getLogo().getUrl().isEmpty()) {
            imageOrgaoRecebedor = ImageIO.read(new File(prefeitura.getLogo().getUrl() + prefeitura.getLogo().getNome()));
        }


        /*
         * ====================================== Informando os dados do
         * contribuinte ======================================
         */

        String nome = imovel.getProprietarios().get(0).getTipoDocumento().getTipo().equals(TipoDocumento.CPF.getTipo()) ? imovel.getProprietarios().get(0).getNome() : imovel.getImovel().getProprietarios().get(0).getNomeFantasia();
        String documento = imovel.getProprietarios().get(0).getTipoDocumento().getTipo().equals(TipoDocumento.CPF.getTipo()) ? imovel.getProprietarios().get(0).getCpf() : imovel.getProprietarios().get(0).getCnpj();

        br.com.nordestefomento.jrimum.domkee.financeiro.banco.febraban.guia.Contribuinte contribuinte = new br.com.nordestefomento.jrimum.domkee.financeiro.banco.febraban.guia.Contribuinte("NOME: " + nome, documento == null || documento.length() == 0 ? "00000000000" : documento);

        /*
         * ====================================== Informando os dados do
         * orgao/empresa recebedor ======================================
         */

        OrgaoRecebedor orgaoRecebedor = new OrgaoRecebedor(prefeitura.getNome(), TipoSeguimento.PREFEITURA);
        orgaoRecebedor.setCodigoDeIdentificacaoFebraban(new CodigoDeIdentificacaoFebraban(prefeitura.getCodigoFebraban()));
        // Se houver uma imagem(Ex: logo) do órgão recebedor...
        if (ObjectUtil.isNotNull(imageOrgaoRecebedor)) {
            orgaoRecebedor.setImgLogo(imageOrgaoRecebedor);
        }

        /*
         * ====================================== Informando os dados do
         * convênio ======================================
         */
        Convenio convenio = new Convenio();
        if (agencia.length == 2) {
            convenio.setAgencia(new Agencia(Integer.parseInt(agencia[0]), agencia[1]));
        }
        br.com.nordestefomento.jrimum.domkee.financeiro.banco.febraban.Banco banco = BancoSuportado.BANCO_DO_BRASIL.create();
        br.com.nordestefomento.jrimum.domkee.financeiro.banco.febraban.ContaBancaria contaB = new br.com.nordestefomento.jrimum.domkee.financeiro.banco.febraban.ContaBancaria();
        contaB.setAgencia(new Agencia(Integer.parseInt(agencia[0]), agencia[1]));
        if (prefeitura.getBancoCarteira() != null) {
            br.com.nordestefomento.jrimum.domkee.financeiro.banco.febraban.Carteira carteira = new br.com.nordestefomento.jrimum.domkee.financeiro.banco.febraban.Carteira(Integer.parseInt(prefeitura.getBancoCarteira()), br.com.nordestefomento.jrimum.domkee.financeiro.banco.febraban.TipoDeCobranca.COM_REGISTRO);
            contaB.setCarteira(carteira);
        }
        banco.addContaBancaria(contaB);
        convenio.setBanco(banco);
        convenio.setNumero(Integer.parseInt(prefeitura.getBancoNumeroConvenio()));

        /*
         * ====================================== Informando dados da
         * Arrecadação ======================================
         */
        Arrecadacao arrecadacao = new Arrecadacao(orgaoRecebedor, contribuinte, convenio);

        BigDecimal valorTotal;
        List<Forus> lstForus = null;
        for (Averbacao avv : getAverbacoes(imovel)) {
            lstForus = forusPendentes(avv, imovel);            
            for(Forus f : lstForus){
                System.out.println(f.getDataForus()+" - "+ f.getValor());
                
            }
            
        }



//        String nossoNumero = forus.getId() + "00";
        String nossoNumero = "00";
        while (nossoNumero.length() < 14) {
            nossoNumero = "0" + nossoNumero;
        }

        //TODO Alterar Codigo Nosso Numero
        nossoNumero = "555" + nossoNumero;
        arrecadacao.setNossoNumero(nossoNumero);

        arrecadacao.setValorDocumento(somaForus(imovel));
        arrecadacao.setTipoValorReferencia(TipoValorReferencia.QUANTIDADE_DE_MOEDA_COM_DV_MODULO_10);
        arrecadacao.setDataDoDocumento(GregorianCalendar.getInstance().getTime());
        File templatePersonalizado = new File(ClassLoaders.getResource("/br/com/foxinline/relatorio/iptu/MODELO_PARCELA_REQUERIMENTO.pdf").getFile());
        Calendar calendar = GregorianCalendar.getInstance();

        calendar.setTime(new Date());
        int x = calendar.get(Calendar.YEAR);
        int d = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
        calendar.set(x, Calendar.DECEMBER, d);
//        calendar.add(Calendar.DAY_OF_MONTH, 2);
        arrecadacao.setDataDoVencimento(calendar.getTime());

        /*
         * ====================================== Informando dados da Guia
         * ======================================
         */

        Guia guia = new Guia(arrecadacao);

        guia.setInstrucaoAoCaixa1("PAGAMENTO SOMENTE À VISTA NO BANCO DO BRASIL.");
        guia.setInstrucaoAoCaixa2("PREFERENCIAMENTE DEVE SER PAGA NOS TERMINAIS DE AUTO-ATENDIMENTO,");
        guia.setInstrucaoAoCaixa3("CORRESPONDENTES BANCÁRIOS E INTERNET");

        // GuiaViewer é o responsável por prover uma visualização da guia.
        GuiaViewer guiaViewer = new GuiaViewer(guia);

        // Se houver um template personalizado, com campos extras, novas informações podem
        // ser adicionadas.
        if (ObjectUtil.isNotNull(templatePersonalizado)) {
            guia.addTextosExtras("txtValorDocumento2", "R$ " + arrecadacao.getValorDocumento().toString());
            guia.addTextosExtras("txtParcela", "UNICA");
            guia.addTextosExtras("txtParcela1", "UNICA");
            guia.addTextosExtras("txtNossoNumero", arrecadacao.getNossoNumero());
            guia.addTextosExtras("txtNossoNumero1", arrecadacao.getNossoNumero());
            guiaViewer = new GuiaViewer(guia);
            guiaViewer.setTemplate(templatePersonalizado);
        }


        // Gerando o arquivo. No caso o arquivo mencionado será salvo na mesma
        // pasta do projeto. Outros exemplos:
        // WINDOWS: boletoViewer.getAsPDF("C:/Temp/MeuBoleto.pdf");
        // LINUX: boletoViewer.getAsPDF("/home/temp/MeuBoleto.pdf");
        // File arquivoPdf = guiaViewer.getPdfAsFile("/opt/MinhaPrimeiraGuia.pdf");

        try {
            List<byte[]> boletosEmBytes = new ArrayList<byte[]>();
            boletosEmBytes.add(guiaViewer.getPdfAsByteArray());
            File arq = Files.bytesToFile("carneRequerimento.pdf", mergeFilesInPages(boletosEmBytes));
            RelatorioServico.genReport(Files.fileToBytes(arq));

            // Mostrando o boleto gerado na tela.
        } catch (DocumentException ex) {
            Logger.getLogger(RequerimentoServico.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(RequerimentoServico.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public static byte[] mergeFilesInPages(List<byte[]> pdfFilesAsByteArray) throws DocumentException, IOException {

        Document document = new Document();
        ByteArrayOutputStream byteOS = new ByteArrayOutputStream();

        PdfWriter writer = PdfWriter.getInstance(document, byteOS);

        document.open();

        PdfContentByte cb = writer.getDirectContent();
        float positionAnterior = 0;



        //Para cada arquivo da lista, cria-se um PdfReader, responsável por ler o arquivo PDF e recuperar informações dele.
        for (byte[] pdfFile : pdfFilesAsByteArray) {

            PdfReader reader = new PdfReader(pdfFile);


            //Faz o processo de mesclagem por página do arquivo, começando pela de número 1.
            for (int i = 1; i <= reader.getNumberOfPages(); i++) {

                float documentHeight = cb.getPdfDocument().getPageSize().getHeight();

                //Importa a página do PDF de origem
                PdfImportedPage page = writer.getImportedPage(reader, i);
                positionAnterior = page.getHeight() * 4;
                float pagePosition = positionAnterior;

                /*
                 * Se a altura restante no documento de destino form menor que a
                 * altura do documento, cria-se uma nova página no documento de
                 * destino.
                 */
                if ((documentHeight - positionAnterior) <= page.getHeight()) {
                    document.newPage();
                    pagePosition = 0;
                    positionAnterior = 0;
                }

                //Adiciona a página ao PDF destino
                cb.addTemplate(page, 0, pagePosition);

                positionAnterior += page.getHeight();
            }
        }

        byteOS.flush();
        document.close();

        byte[] arquivoEmBytes = byteOS.toByteArray();
        byteOS.close();

        return arquivoEmBytes;
    }
}
